-module(acell). -export([indicesList/1,matrix/1,printMatrix/1, clamp/1,addState/2,writeState/2,stateWriterBody/0,createStateWriter/0, initialCellBody/4,cellBody/6,createCell/4,isBaseState/1, delay/2,init/0]). %% acell.erl %% Eric Rollins 2006 %% Written for open-source Erlang, http://www.erlang.org/ %% %% This program uses Erlang processes to model cells in a three-dimensional %% asynchronous cellular automata. % Matrix is square three dimensional array. indicesList(N) -> [{X, Y, Z} || X <- lists:seq(0,N-1), Y <- lists:seq(0,N-1), Z <- lists:seq(0,N-1)]. matrix(N) -> Ma = dict:new(), F = fun(Key,M) -> dict:store(Key,nil,M) end, Indices = indicesList(N), lists:foldl(F,Ma,Indices). printMatrix(M) -> Keys = dict:fetch_keys(M), F = fun(Key) -> io:write(Key), io:fwrite(":",[]), io:write(dict:fetch(Key,M)), io:fwrite(" ",[]) end, lists:foreach(F,Keys), io:fwrite("\n",[]). % Returns value restricted to range 0.0 .. 1.0 clamp(Value) -> if Value < 0.0 -> V1 = 0.0; true -> V1 = Value end, if V1 > 1.0 -> V2 = 1.0; true -> V2 = V1 end, V2. addState({CurR,CurG,CurB},{IncrR,IncrG,IncrB}) -> {clamp(CurR+IncrR), clamp(CurG+IncrG), clamp(CurB+IncrB)}. writeState({X,Y,Z},{R,G,B}) -> {Ok,Fdesc} = file:open("outfile.txt",[write,append]), io:write(Fdesc,X), io:fwrite(Fdesc,",",[]), io:write(Fdesc,Y), io:fwrite(Fdesc,",",[]), io:write(Fdesc,Z), io:fwrite(Fdesc,":",[]), io:write(Fdesc,R), io:fwrite(Fdesc,",",[]), io:write(Fdesc,G), io:fwrite(Fdesc,",",[]), io:write(Fdesc,B), io:fwrite(Fdesc,"\n",[]), file:close(Fdesc). stateWriterBody() -> receive {Loc,State} -> writeState(Loc,State); AnyMessage -> % For debugging. writeState({AnyMessage,-1,-1},{-1,-1,-1}) end, stateWriterBody(). % A single process writes state file, to synchronize access. createStateWriter() -> spawn(acell,stateWriterBody,[]). isBaseState({R,G,B}) -> if R > 0.0 -> false; G > 0.0 -> false; B > 0.0 -> false; true -> true end. delay(TimeStep,CallTime) -> TimeDiff = TimeStep - timer:now_diff(now(),CallTime), if TimeDiff > 0 -> timer:sleep(TimeDiff); true -> true end. initialCellBody(Loc,State,StateWriter,TimeStep) -> receive InNeighbors -> Neighbors = InNeighbors end, cellBody(Loc,State,StateWriter,Neighbors,TimeStep,now()). % This routine forms the inner loop for the cell. cellBody(Loc,State,StateWriter,Neighbors,TimeStep,CallTime) -> {NeighborN,NeighborS,NeighborE,NeighborW,NeighborP,NeighborM} = Neighbors, IsBaseState = isBaseState(State), if IsBaseState == true -> Timeout = 10000000; true -> Timeout = TimeStep end, receive {StateIncr,Direction} -> NewState = addState(State,StateIncr), StateWriter ! {Loc,NewState}, if Direction == n andalso NeighborN /= nil -> delay(TimeStep,CallTime), NeighborN ! {StateIncr,Direction}; Direction == s andalso NeighborS /= nil -> delay(TimeStep,CallTime), NeighborS ! {StateIncr,Direction}; Direction == e andalso NeighborE /= nil -> delay(TimeStep,CallTime), NeighborE ! {StateIncr,Direction}; Direction == w andalso NeighborW /= nil -> delay(TimeStep,CallTime), NeighborW ! {StateIncr,Direction}; Direction == p andalso NeighborP /= nil -> delay(TimeStep,CallTime), NeighborP ! {StateIncr,Direction}; Direction == m andalso NeighborM /= nil -> delay(TimeStep,CallTime), NeighborM ! {StateIncr,Direction}; true -> false end after Timeout -> NewState = State end, delay(TimeStep,CallTime), IsBaseState2 = isBaseState(NewState), if IsBaseState2 == false -> NewState2 = addState(NewState,{-0.2,-0.2,-0.2}), StateWriter ! {Loc,NewState2}; true -> NewState2 = NewState end, cellBody(Loc,NewState2,StateWriter,Neighbors,TimeStep,now()). createCell(Loc,State,StateWriter,TimeStep) -> spawn(acell,initialCellBody,[Loc,State,StateWriter,TimeStep]). init() -> % 50x50x50 = 125,000 processes works (with TimeStep of 3 seconnds). DimSize = 50, TimeStep = 3000, SW = createStateWriter(), % Matrix of cell processes, % Two larger than dimension so edges will be null. M1 = matrix(DimSize+2), % First Create processes. Indices = indicesList(DimSize+1), F = fun(Key,M) -> {X,Y,Z} = Key, if X > 0 andalso Y > 0 andalso Z > 0 -> C = createCell(Key,{0,0,0},SW,TimeStep), % C ! {nil,nil,nil,nil,nil,nil}, dict:store(Key,C,M); true -> M end end, M2 = lists:foldl(F,M1,Indices), % Now set Neighbors. F2 = fun(Key) -> {X,Y,Z} = Key, if X > 0 andalso Y > 0 andalso Z > 0 -> Cell = dict:fetch(Key,M2), NKey = {X,Y+1,Z}, SKey = {X,Y-1,Z}, EKey = {X+1,Y,Z}, WKey = {X-1,Y,Z}, PKey = {X,Y,Z+1}, MKey = {X,Y,Z-1}, NCell = dict:fetch(NKey,M2), SCell = dict:fetch(SKey,M2), ECell = dict:fetch(EKey,M2), WCell = dict:fetch(WKey,M2), PCell = dict:fetch(PKey,M2), MCell = dict:fetch(MKey,M2), Cell ! {NCell,SCell,ECell,WCell,PCell,MCell}; true -> true end end, lists:foreach(F2,Indices), % Add six inputs, travelling East, North, and Plus. OffCenter = (DimSize+2)div 4, dict:fetch({1,OffCenter,OffCenter},M2) ! {{1,0,0},e}, dict:fetch({1,3*OffCenter,OffCenter},M2) ! {{1,0,0},e}, dict:fetch({OffCenter,1,OffCenter},M2) ! {{0,1,0},n}, dict:fetch({3*OffCenter,1,OffCenter},M2) ! {{0,1,0},n}, dict:fetch({OffCenter,OffCenter,1},M2) ! {{0,0,1},p}, dict:fetch({3*OffCenter,OffCenter,1},M2) ! {{0,0,1},p}.